package com.jack.payment.util.common;

import com.github.junrar.Archive;
import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;


import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;


@Component
public class DownloadUtil {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     *  下载
     * @param savePath   下载保存的路径
     * @param url         网络地址
     * @return
     */
    @Async
    public CompletableFuture<String> downloadData(String savePath, String saveFolds, String url, String id) {
        try {
            File saveFile = new File(savePath);
            FileUtils.copyURLToFile(new URL(url), saveFile);
            if (url.endsWith(".rar")) {
                String path = saveFolds + id;
                unzipFile(saveFile, path);
                zipFolder(path, path + ".zip");
                saveFile.delete();
            }
            return CompletableFuture.completedFuture(id);
        } catch (Exception e) {
            log.error("下载URL: {} 数据失败, 请检查 URL 地址或 保存数据路径{}", url, savePath);
            return CompletableFuture.failedFuture(e);
        }
    }


    public  void zipFolder(String srcFolder, String zipFilePath) throws IOException {
        File srcDir = new File(srcFolder);
        if (!srcDir.exists()) {
            throw new IOException(srcDir.getAbsolutePath() + " does not exist");
        }
        ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath));
        addFolderToZip("", srcDir, zipOut);
        zipOut.close();
    }
    private  void addFolderToZip(String path, File srcFolder, ZipOutputStream zipOut) throws IOException {
        File[] files = srcFolder.listFiles();
        String filePath;

        if (files != null && files.length > 0) {
            for (File file : files) {
                if (path.equals("")) {
                    filePath = file.getName();
                } else {
                    filePath = path + File.separator + file.getName();
                }

                if (file.isDirectory()) {
                    // 如果是目录，则递归添加
                    addFolderToZip(filePath, file, zipOut);
                } else {
                    // 如果是文件，则添加到zip
                    byte[] buf = new byte[1024];
                    int len;
                    FileInputStream in = new FileInputStream(file.getAbsolutePath());
                    zipOut.putNextEntry(new ZipEntry(filePath));
                    while ((len = in.read(buf)) > 0) {
                        zipOut.write(buf, 0, len);
                    }
                    zipOut.closeEntry();
                    in.close();
                }
            }
        }
    }
    /**
     * 压缩文件解压 处理
     * @param originZip
     * @param savePath
     */
    public void unzipFile(File originZip, String savePath) throws IOException, RarException {
        if (!originZip.exists()) {
            return;
        }
        List<File> fileList = new ArrayList<>();
        if (originZip.getName().endsWith(".zip")) {
            try (ZipInputStream zips = new ZipInputStream(new FileInputStream(originZip))) {
                byte[] buffer = new byte[1024];
                ZipEntry ze;
                while ((ze = zips.getNextEntry()) != null) {
                    String entryName = ze.getName();
                    File extractedFile = new File(savePath + entryName);
                    if (ze.isDirectory()) {
                        extractedFile.mkdirs();
                    } else {
                        extractedFile.getParentFile().mkdirs(); // 确保父目录存在
                        try (FileOutputStream fos = new FileOutputStream(extractedFile)) {
                            int len;
                            while ((len = zips.read(buffer)) > 0) {
                                fos.write(buffer, 0, len);
                            }
                        }
                        fileList.add(extractedFile);
                    }
                }
            }
        } else if (originZip.getName().endsWith(".rar")) {
            try (Archive archive = new Archive(new FileInputStream(originZip))) {
                List<FileHeader> fileHeaders = archive.getFileHeaders();
                for (FileHeader fileHeader : fileHeaders) {
                    String fileName = fileHeader.getFileName();
                    if (validFileName(fileName)) {              // 排除没必要的下载
                        continue;
                    }
                    fileName = suffixFileName(fileName);
                    File subFile = new File(savePath + fileName);
                    if (fileHeader.isDirectory()) {
                        subFile.mkdirs();
                    } else {
                        subFile.getParentFile().mkdirs();
                        try (InputStream is = archive.getInputStream(fileHeader);
                             FileOutputStream os = new FileOutputStream(subFile)) {
                            byte[] buffer = new byte[4096]; // 更大的缓冲区可能更快
                            int len;
                            while ((len = is.read(buffer)) > 0) {
                                os.write(buffer, 0, len);
                            }
                        }
                    }
                }
            }
        }
    }
    /**
     *  排除不必要的解压
     */
    private static String[] discard = {"ReadMe.txt", "下载字体.url", "下载网页模板.url", "下载网页特效.url"};
    private static boolean validFileName(String fileName) {
        if (StringUtil.isEmpty(fileName)) {
            return true;
        }
        for (String str : discard) {
            if (str.equals(fileName)) {
                return true;
            }
        }
        return false;
    }
    private String suffixFileName(String fileName) {
        if (fileName.startsWith("html")) {
            return fileName.substring(4);
        }
        return fileName;
    }

}
